home *** CD-ROM | disk | FTP | other *** search
Modula Implementation | 1994-09-22 | 10.9 KB | 451 lines |
- IMPLEMENTATION MODULE LongMathLib0;
- FROM Terminal IMPORT WriteString,WriteLn;
- FROM SYSTEM IMPORT LONG;
- FROM System IMPORT FLOATd, TRUNCd;
- FROM RealInOut IMPORT Rec, Long;
-
- (* Methods and approximations are taken from
- HART et al,
- Computer Approximations,
- SIAM Series in Applied Mathematics,
- John Wiley and Sons,
- New York, 1968
- *)
- TYPE RealCard = RECORD
- CASE : BOOLEAN OF
- FALSE: x : LONGREAL |
- TRUE : y : CARDINAL;
- END;
- END;
-
- CONST RedMax = 32;
-
- VAR x,y,z : LONGREAL;
- NegSign : BOOLEAN;
- shift : RECORD
- CASE : BOOLEAN OF
- TRUE : I : INTEGER |
- FALSE : C : CARDINAL
- END
- END;
- n : CARDINAL;
-
- (* "CONSTANTS": *)
- Red : ARRAY [1..RedMax] OF LONGREAL;
- Nul,One,Two,Three,Four,Ten,Three70,Half,RTen,TwoPi,PiH,PiQ,Pi2,Pi4,
- TanPi8,Sqrt2,Sqrt21,Ln2,
- EM140,E150,EM150,EM15 : LONGREAL;
- NulI : LONGINT;
-
- SinPar : RECORD P0,P1,P2,P3,P4,P5,Q0,Q1 : LONGREAL END;
- TanPar : RECORD P0,P1,P2,P3,P4, Q0,Q1,Q2 : LONGREAL END;
- LnPar : RECORD P0,P1,P2,P3, Q0,Q1,Q2 : LONGREAL END;
- ExpPar : RECORD P0,P1, Q0,Q1 : LONGREAL END;
- SqrtPar : RECORD P0,P1,P2,P3, Q0,Q1,Q2 : LONGREAL END;
- ArctanPar : RECORD P0,P1,P2,P3,P4, Q0,Q1,Q2,Q3 : LONGREAL END;
-
- PROCEDURE Entier(x : LONGREAL) : LONGINT;
- BEGIN
- NegSign:=x<Nul;
- x:=ABS(x);
- IF x>FLOATd(MAX(LONGINT)) THEN
- WriteLn;
- WriteString('Error: LONGREAL too large in Entier ');
- WriteLn;
- HALT;
- RETURN 0
- END;
- IF NegSign THEN
- RETURN -(TRUNCd(x)+LONG(1))
- ELSE
- RETURN TRUNCd(x)
- END
- END Entier;
-
- PROCEDURE LongReal(x : LONGINT) : LONGREAL;
- BEGIN
- IF x<NulI THEN
- RETURN -FLOATd(ABS(x))
- ELSE
- RETURN FLOATd(x)
- END
- END LongReal;
-
- PROCEDURE Ln(A : LONGREAL) : LONGREAL;
- VAR b : RealCard;
- (* Hart function 2705 *)
- BEGIN
- IF A<=Nul THEN
- WriteLn;
- WriteString('Error: Ln of value<=0.0 ');
- WriteLn;
- HALT;
- RETURN Nul
- END;
- b.x:=A;
- shift.I:=b.y DIV 10H;
- DEC(shift.I,3FEH); (*shift.I by power of 2*)
- b.y:= 3FE0H+(b.y MOD 10H); (*b now in range 0.5..1.0*)
- z:=b.x;
- WHILE z<Sqrt21 DO
- DEC(shift.I);
- z:=Two*z; (*can be improved - use shifts etc*)
- END;
- z:=(z-One)*Rec(z+One);
- y:=z*z;
- WITH LnPar DO
- y:=z*(((P3*y+P2)*y+P1)*y+P0)*Rec(((y+Q2)*y+Q1)*y+Q0)
- END;
- (* now factor shift.I back in using the fact that
- ln(2^n*x)=ln(2^n)+ln(x)=n*ln(2)+ln(x) *)
- RETURN y+LongReal(shift.I)*Ln2
- END Ln;
-
- PROCEDURE Exp(A : LONGREAL) : LONGREAL;
- (* Hart function 1801*)
- VAR b : RealCard;
- n : INTEGER;
- BEGIN
- IF A<Nul THEN
- b.x:=-A;
- IF b.x>Three70 THEN RETURN Nul END;
- NegSign:=TRUE;
- ELSE
- b.x:=A;
- IF A>Three70 THEN
- WriteLn;
- WriteString('Error: value too large in Exp');
- WriteLn;
- HALT;
- RETURN Nul
- END;
- NegSign:=FALSE;
- END;
- shift.I:=b.y DIV 10H;
- DEC(shift.I,3FBH); (*shift.I by power of 2*)
- IF shift.I>0 THEN
- b.y:=3FB0H+(b.y MOD 10H) (*b now in range 0..1/32*)
- ELSE
- shift.I:=0
- END;
- y:=b.x*b.x;
- WITH ExpPar DO
- z:=P1*y+P0;
- y:=One+(Two*b.x*z)*Rec(((y+Q1)*y+Q0)-b.x*z)
- END;
- FOR n:=shift.I TO 1 BY -1 DO
- y:=y*y;
- END;
- IF NegSign THEN y:=Rec(y) END;
- RETURN y;
- END Exp;
-
- PROCEDURE Sqrt(A : LONGREAL) : LONGREAL;
- VAR b : RealCard;
- exp : CARDINAL;
- BEGIN
- IF A=Nul THEN RETURN A END;
- IF A<Nul THEN
- WriteLn;
- WriteString('Error: Sqrt of value<0.0 ');
- WriteLn;
- HALT;
- RETURN Nul
- END;
- b.x:=A;
- shift.I:=b.y DIV 10H;
- DEC(shift.I,3FEH); (*shift.I by power of 2*)
- IF ODD(shift.I) THEN
- exp:=3FD0H;
- INC(shift.I)
- ELSE
- exp:=3FE0H
- END;
- b.y:=exp + b.y MOD 10H; (*b.x now in [0..1/2]*)
- x:=b.x;
- WITH SqrtPar DO
- y:=((((P3*x)+P2)*x+P1)*x+P0)*Rec(((x+Q2)*x+Q1)*x+Q0)
- END;
- (*this is the first guess at a result*)
- REPEAT
- z:=Half*(x*Rec(y)-y);
- y:=y+z;
- UNTIL ABS(z)<EM15;
- (* now add size back in *)
- IF shift.I<>0 THEN
- b.x:=y;
- INC(b.y,(shift.C DIV 2)*10H);
- RETURN b.x
- ELSE
- RETURN y;
- END;
- END Sqrt;
-
- PROCEDURE Reduce(VAR x : LONGREAL);
- BEGIN
- IF x>Red[RedMax] THEN
- WriteLn;
- WriteString('Error: Too big argument in long trig. function');
- WriteLn;
- HALT;
- x:=Nul;
- RETURN
- END;
- n:=1;
- WHILE x>Red[n] DO INC(n) END;
- IF n>1 THEN
- FOR n:=n-1 TO 1 BY -1 DO
- WHILE x>Red[n] DO x:=x-Red[n] END
- END
- END
- END Reduce;
-
- PROCEDURE Sin(A : LONGREAL) : LONGREAL;
- BEGIN
- (* Hart function no 3369 *)
- IF A<Nul THEN
- NegSign:=TRUE;
- x:=-A;
- ELSE
- NegSign:=FALSE;
- x:=A;
- END;
- Reduce(x);
- IF x>Pi THEN
- NegSign:=NOT NegSign;
- x:=x-Pi;
- END;
- IF x>PiH THEN
- x:=Pi-x;
- END;
- x:=Pi2*x;
- y:=x*x;
- WITH SinPar DO
- y:=x*(((((P5*y+P4)*y+P3)*y+P2)*y+P1)*y+P0)*Rec((y+Q1)*y+Q0)
- END;
- IF NegSign THEN
- RETURN -y
- ELSE
- RETURN y
- END;
- END Sin;
-
- PROCEDURE Cos(A : LONGREAL) : LONGREAL;
- BEGIN
- RETURN Sin(A+PiH); (*can do better - eg Hart 3843*)
- END Cos;
-
- PROCEDURE Tan(A : LONGREAL) : LONGREAL;
- PROCEDURE Hart4285(A : LONGREAL) : LONGREAL;
- BEGIN
- x:=Pi4*A;
- y:=x*x;
- WITH TanPar DO
- RETURN x*((((P4*y+P3)*y+P2)*y+P1)*y+P0)*Rec(((y+Q2)*y+Q1)*y+Q0)
- END
- END Hart4285;
- BEGIN
- IF A<Nul THEN
- x:=-A;
- NegSign:=TRUE
- ELSE
- x:=A;
- NegSign:=FALSE
- END;
- Reduce(x);
- IF x>Pi THEN x:=x-Pi END;
- IF x>(PiH) THEN
- x:=Pi-x;
- NegSign:=NOT NegSign;
- END;
- IF x>(PiQ) THEN
- z:=x;
- x:=(PiH-x);
- IF x<EM140 THEN
- WriteLn;
- WriteString('Error: Tan too close to Pi/2');
- WriteLn;
- y:=E150;
- ELSE
- z:=Hart4285(x);
- y:=Rec(z);
- END;
- ELSE
- y:=Hart4285(x)
- END;
- IF NegSign THEN
- RETURN -y
- ELSE
- RETURN y
- END;
- END Tan;
-
- PROCEDURE Arctan(A : LONGREAL) : LONGREAL;
- VAR NegSign:BOOLEAN;
- PROCEDURE Hart5076(x : LONGREAL) : LONGREAL;
- (*The polynomial approximation to arctan on [0..Pi/8] *)
- BEGIN
- y:=x*x;
- WITH ArctanPar DO
- RETURN x*((((P4*y+P3)*y+P2)*y+P1)*y+P0)*
- Rec((((y+Q3)*y+Q2)*y+Q1)*y+Q0)
- END
- END Hart5076;
- BEGIN
- IF A<Nul THEN
- NegSign:=TRUE;
- A:=-A;
- ELSE
- NegSign:=FALSE;
- END;
- IF A>EM15 THEN
- (* Reduce range to be in [0..tan(Pi/8)]*)
- IF A=One THEN
- A:=PiQ
- ELSIF A>One THEN
- A:=PiH-Arctan(Rec(A))
- ELSIF A>=TanPi8 (*Tan(Pi/8)*) THEN
- A:=PiQ-Hart5076(Two*Rec(One+A)-One)
- ELSE
- A:=Hart5076(A);
- END;
- END;
- IF NegSign THEN
- RETURN -A
- ELSE
- RETURN A
- END;
- END Arctan;
-
- PROCEDURE Arctan2(Y, X : LONGREAL) : LONGREAL;
- VAR Quadrant :CARDINAL;
- BEGIN
- IF (X>=Nul) THEN
- IF Y>=Nul THEN
- Quadrant:=1
- ELSE
- Y:=-Y;
- Quadrant:=4;
- END
- ELSE
- X:=-X;
- IF Y>=Nul THEN
- Quadrant:=2
- ELSE
- Y:=-Y;
- Quadrant:=3;
- END;
- END;
- IF X<=EM150*Y THEN
- x:=PiH
- ELSE x:=Arctan(Y*Rec(X)) END;
- CASE Quadrant OF
- 1: RETURN x |
- 2: RETURN Pi-x |
- 3: RETURN Pi+x |
- 4: RETURN Two*Pi-x
- END;
- END Arctan2;
-
- BEGIN (* Initialisation of "Constants" *)
-
- NulI:=0;
- One:=1.0;
- Ten:=(10.0);
- EM15:=1.0E-15;
- EM140:=Long(1000,0,0,0,0,-140);
- E150 :=Long(1000,0,0,0,0, 150);
- EM150:=Long(1000,0,0,0,0,-150);
-
- Nul:= 0.0;
- Two:= 2.0;
- Three:=3.0;
- Four:= 4.0;
- Three70:=370.0;
- Half:=Rec(Two);
-
- Pi:=Long(3141,5926,5358,9793,2300,0);
- TwoPi:=Two*Pi;
- PiH:=Pi*Rec(Two);
- PiQ:=Pi*Rec(Four);
- Pi2:=Two*Rec(Pi);
- Pi4:=Four*Rec(Pi);
-
- Red[1]:=TwoPi;
- FOR n:=2 TO RedMax DO
- Red[n]:=Three*Red[n-1]
- END;
-
- TanPi8:=Long(4142,1356,2373,0950,4880,-1);
-
- E :=Long(2718,2818,2845,9045,2300,0);
-
- Ln2:=Long(6931,4718,0559,9453,0942,-1);
-
- WITH LnPar DO
- P3:= Long(4210,8737,1217,9797,1450,-1);
- P2:=-Long(9637,6909,3368,6865,9324, 0);
- P1:= Long(3095,7292,8215,3765,0062, 1);
- P0:=-Long(2401,3917,9559,2105,0987, 1);
- Q2:=-Long(8911,1090,2793,7831,2337, 0);
- Q1:= Long(1948,0966,0700,8897,3052, 1);
- Q0:=-Long(1200,6958,9779,6052,5472, 1)
- END;
-
- WITH ExpPar DO
- P1:= Long(2000,1114,1589,9645,6894, 1);
- P0:= Long(8400,6685,2536,4832,3941, 2);
- Q1:= Long(1800,1337,0407,3900,2281, 2);
- Q0:= Long(1680,1337,0507,2966,4841, 3)
- END;
-
- WITH SqrtPar DO
- P3:= Long(2975,3039,1000,0000,0000, 0);
- P2:= Long(2027,7246,3000,0000,0000, 0);
- P1:= Long(1095,4240,5000,0000,0000,-1);
- P0:= Long(3162,3500,0000,0000,0000,-4);
- Q2:= Long(3463,9955,6000,0000,0000, 0);
- Q1:= Long(6412,2536,7000,0000,0000,-1);
- Q0:= Long(9408,9090,0000,0000,0000,-3)
- END;
-
- WITH SinPar DO
- P5:=-Long(2276,7796,5988,7676,1976,-3);
- P4:= Long(2573,8460,9831,1601,9960,-1);
- P3:=-Long(1239,4583,0531,8782,6270, 1);
- P2:= Long(2834,8568,2067,7127,2436, 2);
- P1:=-Long(2707,7267,5338,4732,7688, 3);
- P0:= Long(7024,8302,5674,7977,8974, 3);
- Q1:= Long(1153,0387,1236,1456,1194, 2);
- Q0:= Long(4472,1458,3897,1795,8397, 3)
- END;
-
- WITH TanPar DO
- P4:= Long(3386,6386,4267,7172,0961,-5);
- P3:= Long(3422,5543,8724,1003,4353,-2);
- P2:=-Long(1550,6856,5348,3266,3769, 1);
- P1:= Long(1055,9709,0171,4953,1936, 3);
- P0:=-Long(1306,8202,6475,4825,6683, 4);
- Q2:=-Long(1555,0331,6403,1709,9669, 2);
- Q1:= Long(4765,7513,6291,6483,6989, 3);
- Q0:=-Long(1663,8952,3894,7119,0019, 4)
- END;
-
- WITH ArctanPar DO
- P4:= Long(1589,7402,8848,2307,0480,-1);
- P3:= Long(6660,5790,1700,9262,6575, 0);
- P2:= Long(4096,9264,8321,0225,6374, 1);
- P1:= Long(7747,7687,7192,0420,8616, 1);
- P0:= Long(4454,1340,0592,9068,0320, 1);
- Q3:= Long(1550,3977,5514,2198,7525, 1);
- Q2:= Long(6283,5930,5110,3237,6833, 1);
- Q1:= Long(9232,4801,0723,0097,4841, 1);
- Q0:= Long(4454,1340,0592,9068,0445, 1)
- END;
-
- Sqrt2:=Sqrt(Two);
- Sqrt21:=Rec(Sqrt2);
-
- END LongMathLib0.
-
-